home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / w_timeouts.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  10.9 KB  |  305 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         w_timeout.c
  5. * RCS:          $Header: w_timeouts.c,v 1.4 91/03/14 03:14:17 mayer Exp $
  6. * Description:  WINTERP interfaces to XtAppAddTimeOut() and XtRemoveTimeout().
  7. * Author:       Niels Mayer, HPLabs; Bob Leichner, HPLabs
  8. * Created:      Sat Aug 26 07:44:17 1989
  9. * Modified:     Thu Oct  3 21:08:55 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: w_timeouts.c,v 1.4 91/03/14 03:14:17 mayer Exp $";
  42.  
  43. #include <stdio.h>
  44. #include <Xm/Xm.h>        /* Xm/Xm.h only needed for "winterp.h"*/
  45. #include "winterp.h"
  46. #include "user_prefs.h"
  47. #include "xlisp/xlisp.h"
  48.  
  49. static LVAL s_TIMEOUT_OBJ=NIL, s_TIMEOUT=NIL;
  50.  
  51.  
  52. /******************************************************************************
  53.  * This is called indirectly via XtAppAddTimeOut() in
  54.  *   Wto_Prim_XtAddTimeOut().
  55.  ******************************************************************************/
  56. static void Winterp_TimeoutProc(client_data, id)
  57.      XtPointer     client_data;
  58.      XtIntervalId* id;
  59. {
  60.   extern LVAL          xlenv, xlfenv;
  61.   LVAL                 oldenv, oldfenv, l_evalforms;
  62.   LVAL                 timeout_obj = (LVAL) client_data;
  63.   LVAL                 c_callback = get_timeout_closure(timeout_obj);
  64.  
  65.   /* the timeout-object is no longer active, so indicate that by nulling the timeout-id */
  66.   set_timeout_id(timeout_obj, NULL);
  67.  
  68.   /* remove <timeout_obj> from v_savedobjs allowing it to be garbage collected */
  69.   {
  70.     extern LVAL v_savedobjs;
  71.     int i = Wso_Hash(timeout_obj);
  72.     LVAL l_hbucket = getelement(v_savedobjs, i);
  73.     LVAL l_prev = NIL;
  74.  
  75.     while (l_hbucket && (car(l_hbucket) != timeout_obj)) {
  76.       l_prev = l_hbucket;
  77.       l_hbucket = cdr(l_hbucket);
  78.     }
  79.     if (!l_hbucket)
  80.       xlerror("Internal error in Winterp_TimeoutProc -- couldn't remove <timeout-obj> from v_savedobjs. Hash error?",
  81.           timeout_obj);
  82.     if (!l_prev)        /* first elt matched */
  83.       setelement(v_savedobjs, i, cdr(l_hbucket));
  84.     else
  85.       rplacd(l_prev, cdr(l_hbucket));
  86.   }
  87.  
  88.   /*
  89.    * Now evaluate code associated with timeout -- 
  90.    * Most of this procedure looks alot like xleval.c:evfun(), which is what
  91.    * the evaluator calls when a functional form is to be evaluated. The
  92.    * main difference is that instead of calling xlabind() to bind the
  93.    * formal parameter symbols of a function to their values in the new
  94.    * lexical environment frame returned by xlframe(getenv(fun)), we just
  95.    * bind the symbol "TIMEOUT_OBJ" to the value of the <timeout-obj> that
  96.    * caused this call.
  97.    */
  98.   
  99.   /* protect some pointers */
  100.   xlstkcheck(3);
  101.   xlsave(oldenv);
  102.   xlsave(oldfenv);
  103.   xlsave(l_evalforms);
  104.  
  105.   /* create a new environment frame */
  106.   oldenv = xlenv;
  107.   oldfenv = xlfenv;
  108.   xlenv = xlframe(getenvt(c_callback));    /* note: changed getenv()-->getenvt() due to name conflict with stdlib.h:getenv() */
  109.   xlfenv = getfenv(c_callback);
  110.  
  111.   /* bind the <timeout-object> to locally referrable lexical var TIMEOUT_OBJ */
  112.   xlpbind(s_TIMEOUT_OBJ, timeout_obj, xlenv);
  113.  
  114.   /* execute the block */
  115.   for (l_evalforms = getbody(c_callback); consp(l_evalforms); 
  116.        l_evalforms = cdr(l_evalforms))
  117.     xleval(car(l_evalforms));
  118.   
  119.   /* restore the environment */
  120.   xlenv = oldenv;
  121.   xlfenv = oldfenv;
  122.   
  123.   /* restore the stack */
  124.   xlpopn(3);
  125. }
  126.  
  127.  
  128. /*****************************************************************************
  129.  * This primitive takes two forms of arguments:
  130.  *      (XT_ADD_TIMEOUT <interval> <code>) or
  131.  *      (XT_ADD_TIMEOUT <interval> <timeout-obj>)
  132.  * returns: <timeout_object>
  133.  *
  134.  * <interval> of the timer in milliseconds.
  135.  *
  136.  * <code> is a list of lisp expressions that are evaluated when the timeout
  137.  * occurs. During the timeout, the lexical environment that existed for
  138.  * the call to Xt_Add_Timeout will be used for value and functional bindings.
  139.  * Additionally, the symbol TIMEOUT_OBJ is bound to the <timeout-obj> that caused
  140.  * the timeout.
  141.  *
  142.  * The form (XT_ADD_TIMEOUT <interval> <timeout-obj>) may be used to more
  143.  * efficiently schedule recurrent timeouts. Instead of creating a new closure
  144.  * around the same <code> each time a recurrent timeout is rescheduled,
  145.  * this second form for XT_ADD_TIMEOUT allows you to take the <timeout-obj>
  146.  * from a previously expired timeout and reschedule a new timeout using the 
  147.  * closure setup by the initial call to (XT_ADD_TIMEOUT <interval> <code>).
  148.  * During the execution of <code>, the symbol TIMEOUT_OBJ is bound to 
  149.  * <timout-obj> so that you don't need to keep around a global variable
  150.  * for each recurrent timeout.
  151.  *
  152.  * The returned <timeout-obj> may be passed into the  functions
  153.  * (XT_REMOVE_TIMEOUT <timeout-obj>), or (XT_ADD_TIMEOUT <interval> <timeout-obj>).
  154.  ****************************************************************************/
  155. LVAL Wto_Prim_XtAddTimeOut()
  156. {
  157.   extern XtAppContext app_context; /* winterp.c */
  158.   extern LVAL s_lambda, xlenv, xlfenv;
  159.   LVAL arg, l_code, timeout_obj=NIL;
  160.   long i;
  161.   unsigned long interval;
  162.   
  163.   /* protect some pointers */
  164.   xlsave1(timeout_obj);
  165.  
  166.   /* get interval */
  167.   if ((i = getfixnum(xlgafixnum())) < 0L)
  168.     xlfail("Timeout interval must be a positive integer.");
  169.   else
  170.     interval = (unsigned long) i;
  171.  
  172.   /* get <code> or <timeout_obj> */
  173.   arg = xlgetarg();
  174.   if (timeoutobj_p(arg)) {
  175.     timeout_obj = arg;
  176.     if (get_timeout_id(timeout_obj) != NULL)
  177.       xlerror("Attempt to schedule a recurrent timeout before previous timeout's expiration.", timeout_obj);
  178.   }
  179.   else if (listp(arg))
  180.     l_code = arg;
  181.   else
  182.     xlerror("Bad Argument Type, expected <timeout-code> or <timeout-object>.", arg);
  183.  
  184.   xllastarg();
  185.  
  186.   /* 
  187.    * create the client_data to be sent to Winterp_TimeoutProc. 
  188.    * That procedure takes the client_data==timeout_obj, extracts the closure,
  189.    * and uses this to execute the timeout callback. We also need to retain
  190.    * the timeout identifier for use in RemoveTimeout. For simplicity, we save
  191.    * in lisp object timeout_obj.
  192.    */
  193.  
  194.   /* if args gave <code>, need to create timeout-obj and closure around <code> */
  195.   if (!timeout_obj) {        
  196.     timeout_obj = new_timeoutobj();
  197.     set_timeout_closure(timeout_obj,
  198.             xlclose(s_TIMEOUT, s_lambda, NIL, l_code, xlenv, xlfenv));
  199.   }
  200.  
  201.   set_timeout_id(timeout_obj,
  202.          XtAppAddTimeOut(app_context, interval, Winterp_TimeoutProc, (XtPointer) timeout_obj));  
  203.  
  204.   /*
  205.    * Put timeout_obj in savedobjs so that it gets marked during gc. In that way, we
  206.    * know that the timeout closure (i.e. the callback code, and it's lexical
  207.    * environment) and timeout identifier won't get garbage collected while the
  208.    * timeout-object is "referenced" inside Motif. The timeout_obj gets removed from
  209.    * savedobjs each time the timeout expires, or when xt_remove_timeout gets called.
  210.    */
  211.   { 
  212.     int  i = Wso_Hash(timeout_obj);
  213.     LVAL l_hbucket;
  214.     extern LVAL v_savedobjs;
  215.     
  216.     xlsave1(l_hbucket);
  217.     l_hbucket = cons(timeout_obj, getelement(v_savedobjs, i));
  218.     setelement(v_savedobjs, i, l_hbucket);
  219.     xlpop();
  220.   }
  221.  
  222.   /* resore the stack */
  223.   xlpop();
  224.  
  225.   return (timeout_obj);
  226. }
  227.  
  228.  
  229. /******************************************************************************
  230.  * extern void XtRemoveTimeout();
  231.  *      XtIntervalId timer;      
  232.  * 
  233.  * Lisp:   (xt_remove_timeout <timeout_obj>)
  234.  *         where <timeout_obj> is the value returned by xt_add_timeout.
  235.  ******************************************************************************/
  236. LVAL Wto_Prim_XtRemoveTimeout()
  237. {
  238.   extern LVAL true;
  239.   LVAL timeout_obj;
  240.   
  241.   timeout_obj = xlga_timeoutobj();
  242.   xllastarg();
  243.  
  244.   if (get_timeout_id(timeout_obj) == NULL)
  245.     xlerror("Attempt to remove an expired/removed timeout.", timeout_obj);
  246.   
  247.   XtRemoveTimeOut(get_timeout_id(timeout_obj));
  248.  
  249.   /* the timeout-object is no longer active, so indicate that by nulling the timeout-id */
  250.   set_timeout_id(timeout_obj, NULL);
  251.  
  252.   /* remove <timeout_obj> from v_savedobjs allowing it to be garbage collected */
  253.   {
  254.     extern LVAL v_savedobjs;
  255.     int i = Wso_Hash(timeout_obj);
  256.     LVAL l_hbucket = getelement(v_savedobjs, i);
  257.     LVAL l_prev = NIL;
  258.  
  259.     while (l_hbucket && (car(l_hbucket) != timeout_obj)) {
  260.       l_prev = l_hbucket;
  261.       l_hbucket = cdr(l_hbucket);
  262.     }
  263.     if (!l_hbucket)
  264.       xlerror("Internal error in Wto_Prim_XtRemoveTimeout -- couldn't remove <timeout-obj> from v_savedobjs. Hash error?",
  265.           timeout_obj);
  266.     if (!l_prev)        /* first elt matched */
  267.       setelement(v_savedobjs, i, cdr(l_hbucket));
  268.     else
  269.       rplacd(l_prev, cdr(l_hbucket));
  270.   }
  271.  
  272.   return (true);
  273. }
  274.  
  275.  
  276. /******************************************************************************
  277.  * (TIMEOUT_ACTIVE_P <timeout_obj>)
  278.  *     --> returns T if <timeout_obj> is still scheduled, returns
  279.  *        NIL if <timeout_obj> has expired or if the timeout was
  280.  *        inactivated by XT_REMOVE_TIMEOUT.
  281.  *
  282.  *  <timeout_obj> is the value returned by XT_ADD_TIMEOUT.
  283.  ******************************************************************************/
  284. LVAL Wto_Prim_TIMEOUT_ACTIVE_P()
  285. {
  286.   extern LVAL true;
  287.   LVAL timeout_obj;
  288.   
  289.   timeout_obj = xlga_timeoutobj();
  290.   xllastarg();
  291.   
  292.   return (get_timeout_id(timeout_obj) ? true : NIL);
  293. }
  294.  
  295.  
  296. /******************************************************************************
  297.  *
  298.  ******************************************************************************/
  299. Wto_Init()
  300. {
  301.   s_TIMEOUT_OBJ = xlenter("TIMEOUT_OBJ");
  302.   s_TIMEOUT     = xlenter("XT_TIMEOUT");
  303. }
  304.